package cn.vcjf.weapp.common.wxpay;

import cn.vcjf.weapp.common.util.SysParamUtil;
import cn.vcjf.weapp.common.util.httpUtils.HttpClientUtils;
import cn.vcjf.weapp.common.wxpay.sdk.WXPayConfigImpl;
import cn.vcjf.weapp.common.wxpay.sdk.WXPayUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * 微信官方公众 支付回调
 * @author zhengzihang
 */


public abstract class AbstractWxpayCallback<T>{

    private Logger logger = LogManager.getLogger(this.getClass());
    private static String SUCCESS_RESULT="<xml><return_code><![CDATA[SUCCESS]]></return_code>" +
            "<return_msg><![CDATA[OK]]></return_msg></xml>";
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            T order;
            String requestBodyStr = HttpClientUtils.getRequestBodyStr(request);
            logger.info("监听微信支付通知:{}", requestBodyStr);
            Map<String, String> resContent = WXPayUtil.xmlToMap(requestBodyStr);
//            logger.info("监听微信支付通知:{}", resContent);

            boolean signatureValid;
            if(!SysParamUtil.isTestModel()){
                signatureValid =WXPayUtil.isSignatureValid(resContent, WXPayConfigImpl.KEY);
            }else {
                signatureValid =true;
            }
            String is_test_callback = resContent.get("is_test_callback");
            if("is_test_callback".equals(is_test_callback)){
                signatureValid =true;
            }
            if(!signatureValid){
                logger.info("微信支付回调:签名错误{}",signatureValid);
                response.getWriter().write("FAIL:签名错误");
                return;
            }
            if (StringUtils.isEmpty(resContent.toString())) {
                response.getWriter().write("FAIL");
                return;
            }
            String orderId = resContent.get("out_trade_no");
            String appId = resContent.get("appid");
            if(!SysParamUtil.isTestModel()) {
                if (StringUtils.isEmpty(appId) || !WXPayConfigImpl.APP_ID.equals(appId)) {
                    response.getWriter().write("FAIL:appId错误");
                    return;
                }
            }
            if (StringUtils.isEmpty(orderId)) {
                response.getWriter().write("FAIL:订单号为空");
                return;
            }
            order = this.findOrder(orderId);
            if (null == order) {
                logger.error("未找到订单号{}", orderId);
                response.getWriter().write("FAIL:未找到订单号");
                return;
            }
            if (getSuccessStatusStatus().equals(getOrderStatus(order))) {
                response.getWriter().write(SUCCESS_RESULT);
                return;
            }
            if("SUCCESS".equals(resContent.get("return_code"))&&"SUCCESS".equals(resContent.get("result_code"))){
                String pOrderId = resContent.get("transaction_id");
                //订单成功后
                doOrderSuccess(order,resContent.toString(),pOrderId);

                response.getWriter().write(SUCCESS_RESULT);

            }else if(!"SUCCESS".equals(resContent.get("result_code"))){
                //订单下单中
                doOrderUnding(order,resContent.toString());
                response.getWriter().write("FAIL");
            }else{
                //订单支付失败
                doOrderFailed(order,resContent.toString());
                response.getWriter().write(SUCCESS_RESULT);
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error("微信支付结果处理异常", e);
            response.getWriter().write("FAIL:处理异常");
        }
        return;
    }

    public abstract void cleanOpenId();

    /**
     * 订单支付成功后调用的方法
     * @param order
     * @param res
     * @param pOrderId
     */
    protected abstract void doOrderSuccess(T order,String res,String pOrderId) throws ServletException;
    /**
     * 订单支付失败后调用的方法
     * @param order
     * @param res
     */
    protected abstract void doOrderFailed(T order, String res) throws ServletException;

    /**
     * 订单下单中状态调用的方法
     * @param order
     * @param res
     */
    protected abstract void doOrderUnding(T order, String res) throws ServletException;

    /**
     * 根据订单id查询订单
     * @param orderId
     * @return
     */
    protected abstract T findOrder(String orderId);

    /**
     * 获取订单状态
     * @param order
     * @return
     */
    protected abstract Long getOrderStatus(T order);


    /**
     * 获取订单成功时的状态
     * @return
     */
    protected abstract Long getSuccessStatusStatus();
}
